JS的引入
    引入样式
        import './index.less'
    内嵌式的
        <script> </script>
    外部
        <script src="...js"></script>
        // 中间不允许写代码
        // JS中推荐单引号
        // 外部引入需要一个load事件
        window.addEventListener('load', function(){
            alert()
        }
    行内式
        写在标签中  onclick=""
注释
    //单行注释  ctrl+/
    /* 多行     shift alt a
        注释 */
显示数据
    document.write() 
    //浏览器弹出警示框  展示的输出结果
    window.alert();  
    //浏览器弹出输入框，用户可以输入
    prompt('info'); 
        取过来的值为字符型的
    //浏览器控制台打印输出信息  程序员看的
    console.log( );  
    //浏览器弹出选择 确定为真 取消为假
    confirm()  

变量
    //内存申请的空间，用来存放数据的
    变量初始化
        var age(变量名)= 10; 
        var myname = prompt('请输入你的名字');
    多个变量声明
        var age=18,
            address = 'asdas';
        // ,号隔开
    命名规范
        字母,数字,下划线_ $符号组成
        区分大小写
        不能数字开头
        不能是关键字保留字
        命名有意义
        遵循驼峰命名法
            myFristName
        不能有空格
    //文本用引号，数字不用引号

数据类型
    // js 变量数据类型只有程序在运行过程中根据等号右边的值来判断的
        变量的数据类型可变    
    值类型(基本类型)
        字符串（String）
            用单引号''区分 嵌套外单内双
          字符串转义字符
            /* 
            \n     换行
            \\     斜杠\
            \'     '
            \"     "
            \t     tab 缩进
            \b     空格          */
            length检查获取字符串的长度
                alert(str.length)
            +字符串拼接将两个字符串拼接
            //只要有字符串和其他类型相拼接最终结果是字符串型
            与变量相加
                console(''+ var +'')
        数字(Number)
            //数字前面加0表示八进制  0x表示十六进制
            Number.MAX_VALUE   数字中最大值
            Number.MIN_VALUE        最小值
            NaN    非数字
            isNaN(x)  是数字为 false
                      不是数字为 true
        对空 Null; 返回的是空的Objec
             // 有个变量打算作为存储对象，暂时没想好放什么
        未定义（Undefined）
        Symbol表示独一无二的值
        布尔(Boolean) 
           1 ture; 0 false;

    引用数据类型
        对象(Object)
            自定义对象
                // 无序的相关属性和方法集合
                由属性(特征,名词)和方法(行为,动词)组成

                字面量创建对象
                // 对象由花括号分隔。在括号内部，对象的属性以名称和值对的形式来定义(属性名 ：值)属性由逗号分隔
                // 方法: 后面跟的是一个匿名函数
                    var obj = {
                    name : 'x',
                    age : 18,
                    id :  5566,
                    sayhi: function(){
                        console.log("hii~");
                    }
                    }

                newObject创建对象
                // 等号赋值的方法 添加对象属性和方法  每个属性和方法用分号隔开 
                    var obj = new Object();
                    obj.name = 'x';
                    obj.age = 18;
                    obj.sayhi = function(){
                        console.log('hi');
                    }

                构造函数创建对象
                    // 构造函数名首字母必须大写  不需要return 就可以返回结果
                    function 构造函数名(形参, 形参){
                        this.属性 = 值;
                        this.方法 = function() {

                        }
                    }
                调用函数 
                    // 调用函数后就可以使用对象里面的属性和方法
                    var xx = new 构造函数名(实参, 实参);
                        /* new执行过程
                                new 构造函数可以在内存中创建了一个空的对象
                                this 指向刚才创建的空对象
                                执行构造函数里面的代码，给空对象添加属性和方法
                                返回这个对象  */

                调用属性有两种寻址方式
                    // 对象名.属性名    
                        obj.lastname;
                    // 对象名['属性名']
                        obj["lastname"];
                调用方法
                    对象名.方法名()
                        obj.sayhi();
                遍历对象
                    for(var k (变量) in obj(对象)){
                        console.log(变量);  // 变量 输出 得到的是属性名
                        console.log(对象[变量]);   // 得到的是属性值
                    }
                    // 变量喜欢用 K key 表示

            内置对象(查看文档)
                Math对象
                    绝对值
                        Math.abs()
                    最大值
                        Math.max()
                    随机数
                        Math.random()
                    往大取整
                        Math.ceil()
                    往小取证
                        Math.floor()
                日期对象
                    var date = new Date()
                    没有参数返回系统当前的时间
                    参数常用的写法
                        数字型: 2019, 10,01
                        *字符串型: '2019-10-1'
                    // 倒计时案例、
                        function countDown(time) {
                            var nowTime = +new Date();
                            var inputTime = +new Date();
                            var time = (inputTime - nowTime) / 1000; // 剩余时间总秒速
                            var d = parseInt(time / 60 /60 /24);
                            d = d < 10 ? '0' + d : d;
                            var h = parseInt(time / 60 /60 %24);
                            h = h < 10 ? '0' + h : h;
                            var m = parseInt(time / 60 % 60);
                            m = m < 10 ? '0' + m : m;
                            var s = parseInt(time % 60);
                            s = s < 10 ? '0' + s : s;
                            return d + '天' + h + '时' + m + '分' + s + '秒';
                        }
                
                浏览器对象
                字符串对象
                    indexof();索引号查找
                        // 查找字符串
                        var str = 'abcoefoxyozzoopp';
                        var index = str.indexof('o');
                        var num = 0;
                        while (index !== -1){
                            console.log(index);
                            num++;
                            index = str.indexof('o',index + 1);
                        }
                    join();数组转换为字符型
                        // 填写为转换间隔号  
                    split();字符串转换为数组
                        // 根据填写的间隔号来间隔转换
                    根据位置返回字符
                        charAt(index);
                        charCodeAt(index);
                            // 返回相应索引号字符ASCII值,目的:判断用户按了哪个键
                        str[index];
                            // 获取指定位置处字符 兼容性 
                    substr('截取位置','截取几个字符')
                    replace(被替换字符, 替换为的字符)
                        // 替换第一个字符

        数组(Array)
            // 一组数据的集合，可以存储在单个变量下
            利用new关键字创建数组
                var arr = new Array(); // 创建一个空的数组
                 // var arr = new Array(2)  2表示数组长度为2  里面两个空的元素
                 // var arr = new Array(2,3)  这里有2个素组元素，是2 和3
            *利用数组字面量创建数组
                var arr = [ ];
                // 数组里面的数据用, 分隔
            获取数组中的元素
                // 索引号从0开始  遍历数组用循环
                数组名 [索引号]
                数组名.length  // 获取数组元素的长度
            数组新增元素
                通过修改length长度来实现数组扩容
                 arr.length = 5; // 新增为空
                通过索引号追加
                 arr [4] = ; // 新索引号为追加，原有索引号为替代新元素

            数组对象
                Array.isArray();检测是否为数组

                push(); 数组末尾添加一个或者多个数组元素
                     // arr.push(4); 把4追加到之前的数组后面 返回值为新数组的长度
                unshift();数组前面添加一个或多个数组元素
                     // arr.unshift() 直接写数组元素   返回值为新数组长度
                pop();删除数组最后一个元素
                     // arr.pop() 不用填值， 返回值为删除的元素
                shift();删除数组第一个元素
                     // 不用填值，返回值为第一个元素的值

                reverse();翻转数组
                sort();数组冒泡排序
                     /* arr.sort(function(a,b){
                         retrun a - b; 升序
                         retrun b - a; 降序
                     })               */
                indexOf();数组索引
                     // arr.indexof('bule') 返回第一个满足条件的索引号，返回值为索引号 
                     // 找不到元素返回值为-1;
                     // indexof ('2', 3)重第三个开始查找2
                     lastIndexOf()
                         // 从后面查找    
                splice();
                    删除
                    array.splice(index,n);
                    // index 起始位置  n需要删除的元素个数，
                    插入替换
                    array.splice(index,0,data1,data2,);
                    // index：数组中需要插入数据的起始位置；
                    // 0：插入删除的个数为0； 替换为1
                    // data1,data2：需要插入的元素，用逗号隔开
                
        函数(Function)
            函数声明
                function 函数名(形参1, 形参2) {    // 函数名一般为动词
                    代码
                }

                匿名函数
                var 变量名 = function () {
                } // 调用时以变量名调用
            调用函数
                函数名(实参1, 实参2); 
                /* 变量和参数必须以一致的顺序出现。第一个变量就是第一个被传递的参数的给定的值
                   如果实参的个数多余形参，会取到形参的个数
                   如果实参的个数少于形参，多余的形参会定义为undefined 最终结果时NaN   */
                return X; 返还函数值
                    只能返回一个值返回的结果是最后一个值
                    返回多个值用数组的形式
                return;  退出函数 // 后面的代码不会被执行
                
            arguments
                里面存储了所有传过来的实参
                // 伪数组 具有length属性按照索引方式存储，没有正真数组的 pop() push()   
                只有函数才有
                不知道输入的数量时使用可以不设置形参
                
        typeof 检查数据类型

            立即执行函数
                (function() {}())  /  * (function() {})()  // 不需要调用立马执行 第二个小括号可以看作调用函数
                    创建一个独立的作用域
            
            remove()  // 可以直接删除元素
            click()   // 可以直接调用点击事件
            input.select()  // 文本框文字处于选定状态

    数据类型转换
        转换为字符型 
            变量.toString()
                alert(num.toString )
            String()强制转换
                alert(String(num))
            *加号拼接字符串  
                alert(num + '字符串') //隐式转换
        转换数字型
            *parselnt()函数  转换成整数
                alert(parseInt(变量))
            *parseFloat()函数    转换成浮点数
                alert(parseFloat(变量))
                // 120px     120
                // rem120px  NaN
            Number()
            隐式转换
                console.log('12' - 0) *-/ 
        转换为布尔型
            Boolean()
               // 空的，否定的值 0 会被转换成false 其余的转换成true

    简单数据类型
        值类型string, number, boolean, undefined, null
        // 存放到栈 存放的是值
    复杂数据类型
        引用类型
        // 存放到堆 栈的地址找到堆 
        
运算符
    算数运算符
        - * / + %
        //避免浮点数直接参与运算
    递增递减运算符
        前置递增
            //先自加后返回值
            ++num --num 
            num = num +1
        后置递增
            //先返回值再自减
            num++ num--
    比较运算符
        返回值布尔值
            <     
            >
            <=
            >=
            ==      判等号 //会转型，把字符串转换成数字类型
            !=      
            ===      全等 // 要求值和数据类型都一致
    逻辑运算符
        返回值为布尔值
        &&  与
        ||  或
        !   非
        逻辑中断,左边可以确定结果就不再继续右边运算
            逻辑与
                第一个为真返回表达式二
                第一个为假返回表达式一 
            逻辑或
                第一个为真返还表达式一
                第一个为假返回表达式二
    赋值运算符
        num += 2  num=num +2
            *=
            -=
            /=
            %=
    运算符优先级问题
        小括号       （）
        一元运算符    ++ -- ！
        算数运算符    先*/%后+-
        关系运算符    > >= < <=
        相等运算符    == != === !==
        逻辑运算符    先&& 后||
        赋值运算符    =
        逗号运算符    ,

流程控制
    顺序结构

    分支结构
        if语句
            单分支语句
                if（条件表达式） {
                    //执行语句
                }
                    //条件表达为真时执行括号里语句
            双分支语句
                if (){

                }
                else {
                    //否则
                }
            多分支语句
                if(){

                }
                else if(){
                    //任意多个else if
                }
                else{

                }
        三元表达式
            条件表达式 ? 表达式1 : 表达式2  
            //为真返回表达式1值，假返回表达式2值
        switch语句
            switch(变量) {
                case value1 :
                    执行语句;
                    break;
                case value2 :
                    执行语句;
                    break;
                default:
                    执行最后的语句;
            }    
            不写break继续执行下一条语句直到跳出
        //switch语句通常处理case比较确定值的情况，if更为灵活，通常用于大范围判断
        //分支较少，If语句执行效率更高，分支较多，switch 语句效率跟高
        //swith语句进行条件判断后直接执行到程序的条件语句，效率更高，if有几种条件就得判断多少次
    循环结构
        for循环
            for(初始化变量; 条件表达式; 操作表达式){
                //循环体
            }
            for(var i=1; i<=100; i++){

            }
        while循环
            while(条件表达式) {
                //循环体
            }
            //当条件表达式为真则执行循环体，否则退出循环
            相比for能做更复杂的判断
        dowhile循环
            do {
                //循环体
            }while(条件表达式)
            //先执行一次循环体，再判断条件，条件为真继续执行循环体，否则退出循环
        continue  立即跳出本次循环继续下一次的循环
        break     跳出循环

冒泡排序法
    一次比较两个元素如果顺序错误就换过来
    var arr = [1,4,5,3,2];
    for(var i = 0; i <= arr.length -1; i++) {  // 外层循环趟数
        for ( var j = 0; j <= arr.length -i -1; j++){   // 内层循环每一趟的交换次数
            if(arr[j]>arr[j + 1]){
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }

作用域
    // 代码名字在某个范围内起作用和效果
    全局作用域
        整个script标签或者单独一个js文件
        在全局中都可用
        // 只有浏览器关闭时才会销毁比较占用内存资源
    局部作用域
        在函数内部为局部作用域
        /*
        局部变量只作用于函数内，所以不同的函数可以使用相同名称的变量，在函数开始执行时创建，函数执行完后局部变量会自动销毁。
        变量在函数内没有声明（没有使用 var 关键字），该变量为全局变量。网页中所有脚本和函数均可使用
        */
    作用域链
        内部函数可以访问外部函数的变量,采取的是链式查找的方式决定取那个值
         // 就近原则

预解析
    /* js引擎运行分为两步, 预解析 执行代码
        预解析 js引擎会把js里面所有的var 还有 function 提升到当前作用域的最前面
        代码执行  按照代码书写的顺序从上往下执行 */
        变量提升(预解析),函数提升(预解析)
    // 变量提升就是把所有的变量声明提升到  *当前的作用域最前面* 只提升声明 不提升赋值 
    // 函数声明会被提升，但是函数表达式却不会被提升。   函数会首先被提升，然后才是变量
        // 1   undifine
        console.log(num);     预解析相当于;    var num;
        var num = 10;                         console.log(num);
                                              num = 10;
        // 2    报错
        fun();                              
        var fun = function (){              
            console.log(22)                 
        }
        // 相当于
        var fun;
        fun ();
        fun = function (){
            console.log(22);
        }
    // 函数提升就是把所有的函数声明调用到前面
        函数表达式
        fn ();
        function fn(){
            console.log(11);
        }
        // 相当于
        function fn() {
            console.log(11)
        }
    案例
        // 1   underfind
        var num = 10;
        fun ();
        function fun(){
            console.log(num);
            var num = 20;
        }
        // 相当于
         var num;
         
         function fun(){
             var num;
             console.log(num);
             num = 20;
         }
         num = 10;
         fun();
         // 2 
         f1();
         console.loge(c);
         console.loge(b);
         console.loge(a);
         function f1() {
            var a = b = c = 9;
             console.loge(a);
             console.loge(b);
             console.loge(c);
         }
         // 相当于
         function f1 (){
             var a;
             a =  b = c =9; // 只定义了一个 var a ;其余为全局变量 
             console.loge(a);     // 集体声明 var a=9, b=9, c=9;
             console.loge(b);
             console.loge(c);
         }
         f1 ();
         console.loge(c);
         console.loge(b);
         console.loge(a);

webAPI
    DOM (文档对象模型) // 通过DOM获得的元素是一个对象
        获取元素
            getElementById()
                // 根据ID获取  ID是大小写敏感的字符串 返回的是一个元素对象
                document.getElementById('')
            getElementsByTagName()
                // 根据标签名获取 返回带有标签名的对象的集合以（）  得到的对象是动态的
                document.getElementsByTagName('')
                // 无论页面有没有这个元素 返回的都是伪数组的形式
                element.getElementsByTagName('');指定父元素获取
            getElementsByClassName()
                // 根据类名获得
                document.getElementsByClassName()

            *querySelector()
                // 根据指定选择器返回第一个元素对象    伪数组的形式 之后可以以 var[]形式分别调用 
                document.querySelector('') 
                // ID# 类. 选择器需要接符号
            *querySelectorAll()
                // 返回指定选择器的所有对象    以伪数组的形式返回
            获取特殊元素
                获取body 
                    document.body
                获取html
                    document.docunmentElement
            
        事件   
        // 事件源(事件触发的对象)   事件类型(如何触发,什么事件)   事件处理程序(通过函数赋值的方式完成)
        // 获取元素  注册事件 处理事件
            常见的鼠标事件
                onclick         // 鼠标左键点击
                onmouseover     // 鼠标经过触发
                onmouseout      // 鼠标离开触发
                onfocus         // 获取鼠标焦点触发
                onblur          // 失去鼠标焦点触发
                onmousemove     // 鼠标移动触发
                onmouseup       // 鼠标弹起触发
                onmousedown     // 鼠标按下触发
            常见的键盘事件
                onkeydown       // 某个键盘按键被按下时触发
                onkeyup         // 某个键盘按键被松开时触发
                onkeypress      // 某个键盘按键被按下时触发  不能识别功能键
                    执行顺序: down-press-up
            
            操作元素
                改变元素内容
                    element.innerText // 不识别HTML标签 去除空格和换行
                    *element.innerHTML = ''; // 识别HTML标签  保留空格和换行   标准
                修改表单属性
                    // type, value, checked, selected, disable
                    element.value = '';
                    
                修改样式属性
                    element.style   // 行内样式
                    element.className   // 类名样式 改变当前元素的类  
                        // 要是原先有类名会覆盖掉原来的   采用多类名选择器可以保留（空格隔开）
            属性    
                获取元素属性   
                    element.属性    // 获取内置属性值
                    *element.getAttribute('属性')    // 可以获取自定义属性
                    element.dateset.属性 // H5新增 e11支持 dateset 是一个集合里面存放了所有date开头的自定义属性
                        // 只能获取date-开头 
                设置元素属性值       
                    element.removeAttribute('属性')  // 移除属性
                    element.setAttribute('属性','值'); // 设置自定义属性
                    // 属性 data- 开头自定义属性

            排他思想算法
                所有元素清除样式
                给当前元素设置样式
            
            节点操作
                // 为了获取元素
                节点类型(nodeType),节点名称(nodeName),节点值(nodeValue)
                    元素节点nodeType为1
                    属性节点nodeType为2
                    文本节点nodeType为3

                父级节点
                    *node.parentNode // 得到离元素最近的父节点

                子节点
                    node.childNodes
                        // 返回指定子节点的集合 返回所有的子节点包括元素节点,文本节点
                    node.firstChild 
                        // 返回第一个子节点  包括文本节点还是元素节点
                    node.lastChild
                        // 返回最后一个子节点，包括文本还是元素节点
                
                    *node.children 
                            // 返回所有子元素节点  只返回元素节点
                        // node.children[0] 获取单个元素 .length - 1 最后一个子元素
                    node.firstElementChild 
                        // 返回第一个子元素节点 IE9以上
                    node.lastElementChild   
                        // 返回最后一个子元素节点  IE9以上

                兄弟节点
                    node.nextSibling
                        // 下一个兄弟节点  包含元素结点文本节点等  找不到返回null
                    node.previousSibling
                        // 上一个兄弟节点  包含元素结点文本节点   找不到返回null
                    node.nextElementSibling
                        // 当前元素的下一个兄弟元素节点   兼容性问题 IE9
                    node.previousElementSibling
                        // 当前元素的上一个兄弟元素节点   兼容性问题  IE9

                创建节点 
                        document.createElement('')
                    添加节点 // 先创建再添加
                        node.appendChild(child)  // node 父级  child 子级   后面追加元素
                        node.insertBefore(child, 指定元素)  //  生成在指定元素前
                删除节点
                    node.removeChild(child) // node 父级  child 子级
                复制节点
                    node.clonNode('')
                    // node为克隆元素   括号参数为空或为false则是浅拷贝  只复制标签不复制内容  ture深度拷贝

                innerHTML与createElement区别
                    innerHTML创建多个元素效率更高(不要拼接字符串,采取数组追加的形式,再一次性获得join转换),结构复杂
                    createElement();创建多个元素的效率稍微低,但是结构清晰

        事件高级
            传统注册事件 // on 开头 注册事件的唯一性  上

            监听注册事件 // ie9以前不支持 同一个元素可以注册多个监听器
                监听对象.addEventListener(type, listener,[useCapture]) 
                    type: 事件类型字符串, click, mouseover // 不需要带on， 事件类型是字符串，必定加引号
                        click         // 鼠标左键点击
                        mouseover     // 鼠标经过触发
                        mouseout      // 鼠标离开触发
                        focus         // 获取鼠标焦点触发
                        blur          // 失去鼠标焦点触发
                        mousemove     // 鼠标移动触发
                        mouseup       // 鼠标弹起触发
                        mousedown     // 鼠标按下触发

                        keydown       // 键盘按下触发
                        keypress      // 键盘按下触发
                        keyup         // 键盘弹起触发

                    listener:  事件处理函数,事件发生时会调用该监听函数
                    useCapture: 可选参数,一个是布尔值(默认为false)
                                // false 为冒泡阶段   true 为捕获阶段
                    
                            div.addEventListener('click',function() {  
                                alert('ss');
                            },ture);
                       
                            
            
            删除事件 // 解绑
                传统方式.onclick=null 

                监听事件//   案例   里面的fn不需要 函数调用加（）
                    div.addEventListener('click', fn);
                            function fn() {
                                alert('ss');
                                div.removeEventListener('click', fn);
                            }
            
            DOM事件流
                // 描述的是从页面中接受事件的顺序
                捕获阶段  // 从大到小
                当前目标阶段
                冒泡阶段  // 从小到大 onclick  只能得到冒泡阶段
                 //  onblur onfocus onmouseenter onmouseleave  没有冒泡阶段
              事件对象event
                    div.onclick = function(event) {
                        
                    }
                    div.addEventListener('click',function(event){

                    })
                    // enent当形参看 为事件对象 是一系列相关数据的集合，和事件相关的 鼠标事件得到鼠标相关信息，键盘事件得到了键盘的相关信息
                    // 只有有了事件才能存在 不需要传递参数
                常见的事件对象的属性方法
                    *e.target        // 返回触发事件的对象   this 返回绑定事件的对象
                      e.srcElement          // ie 6-8
                    *e.type          // 返回事件的类型  click
                    *e.preventDefault()  // 阻止默认事件，比如不让链接跳转
                      e.returnValue         // ie6-8
                    *e.stopPropagatio() // 阻止冒泡
                      e.cancelBubble        // ie6-8
                
                事件委托
                    // 不要给每一个子节点单独设置事件监听器,而是事件监听器设置到父结点上,然后利用冒泡原理影响设置每个子节点

                鼠标事件对象
                    // 返回鼠标相对于浏览器窗口可视区的坐标
                        e.clientX       
                        e.clientY
                    // 返回鼠标相对于文档页面的坐标
                        e.pageX        
                        e.pageY
                    // 返回鼠标相对于电脑屏幕的坐标
                        e.screenX      
                        e.screenY
                键盘事件对象
                    e.keyCode     
                    // keyup keydown 不区分字母大小写   keypress 区分大小写
                    // 返回ascii码值
    
    BOM
        浏览器对象模型
        // 浏览器窗口的交互效果 
        window对象
            // 是浏览器顶级对象 是JS访问浏览器窗口的一个接口 window可省略

        窗口加载事件
            window.onload
                // 当文档内容完全加载完成会触发该事件，就调用该函数  包含页面元素，DOM 图片 FLASH CSS
                window.addEventListener('load', function(){
                    var btn = document.querySelector('button');
                    btn.addEventListener('click', function(){

                    })
                })
            DOMContentLoaded // DOM加载完成事件触发， 不包含FALSH CSS 加载速度比load快
                document.addEventListener('DOMContentLoaded', function(){

                })
        调整窗口大小事件
            window.onresize = function(){

            }
            // 调整窗口大小时触发  利用此事件完成响应式布局
            window.addEventListener('resize', function(){

            })
        
        定时器
            setTimeout(调用函数, 延迟毫秒数) 
            // 延迟毫秒可以省略 默认为0 只调用一次   设置变量为全局变量
                // 1
                var time = setTimeout(function(){
                    alert("");
                }, 2000)

                // 2
                function callback(){

                }
                var time = setTimeout(callback, 2000)
            停止定时器
                clearTimeout(timeoutID)
            
            setInterval(回调函数, 间隔的毫秒数)
            // 反复调用一个函数，间隔时间一直调用
            停止定时器  
                clearInterval(ID)
            // 每次开始定时器时先清除定时器保证只有一个定时器

        this指向问题
            全局作用域下的普通函数都指向window,定时器里面的this也指向window
            方法调用中谁调用指向谁
            构造函数中this指向构造函数中的实列

        同步
           // 前一个任务结束后再执行后一个任务,程序的执行顺序与任务排列顺序一致
        异步
           // 做一件事情同时，可以去处理其他事情
            同步任务都是在主线程上执行,形成一个执行栈
            JS异步任务是通过回调函数实现
                异步任务
                    普通事件: click, resize
                    资源加载: load, error 
                    定时器: setInterval, setTimeout
            // 异步任务放到任务队列里面
            // 先执行执行栈的同步任务，遇到回调函数把回调函数先放到任务队列，一旦执行栈中所有同步任务执行完毕，再去按次序执行任务队列的异步任务
        
        location对象
            获取或设置窗体的URL(统一资源定位符)
                protocol            // 通信协议
                host                // 主机域名
                port                // 端口号
                path                // 路径 由零或多个/ 符号分隔开一般用来显示主机上的一个目录文件
                query               // 参数  以键值对的形式通过&分隔开
                fragment            // 片段  #号后面内容 常见于 连接点 锚点
            
            location对象属性
                *location.href           // 获取或设置整个URL
                location.host           // 返回主机域名
                location.port           // 返回端口号
                location.pathname       // 返回路径
                *location.search         // 返回参数
                location.hash           // 返回片段

            location对象方法
                *location.assign()      // 和href一样可以跳转页面 重定向页面   记录浏览历史，可以后退
                location.replace()     // 替换当前页面，因为不记录历史所有不能后退页面
                location.reload()      // 重新加载页面，相当于刷新按钮或者F5 如果参数为true 强制刷新ctrl + F5
            
        navigator对象
            navigator.userAgent   // 判断用户用那个终端打开，实现跳转功能
        
        history对象
            history.back()      // 后退功能
            history.forward()   // 前进功能
            history.go(参数)    // 前进后退功能 1 前进1个页面 -1 后退一个页面
        
        网页特效pc端
            offset
              // 得到任意样式表的样式值
                element.offsetParent            // 返回作为该元素带有定位的父级元素 父级没有定位则返回body
                element.offestTop               // 返回元素相对带有定位的父元素上方的偏移
                element.offestLeft              // 返回元素相对带有定位父元素左边框的偏移
                element.offestWidth             // 返回自身包括padding 边框 内容区的宽度  返回数值不带单位
                element.offestHeight            // 返回自身包括padding 边框 内容区的高度  返回数值不带单位
            
            client
              // 获取可视区的相关信息
                element.clientTop               // 返回元素上边框大小
                element.clientLeft              // 返回元素左边框大小
                element.clientWidth             // 返回自身包括padding  内容区的宽度  不包含边框 返回数值不带单位
                element.clientHeight            // 返回自身包括padding  内容区的高度  不包含边框 返回数值不带单位
            
            scroll
              // 动态得到该元素的大小，滚动距离
                element.scollTop                // 返回被卷去的上侧距离，返回数值不带单位
                element.scollLeft               // 返回被卷去的左侧距离，返回数值不带单位
                element.scollWidth              // 返回自身实际的宽度，不含边框  返回数值不带单位
                element.scollHeight             // 返回自身实际的高度，不含边框  返回数值不带单位
              页面被卷去的头部
                window.pageXOffset 
                windou.pageYOffset
              
                 document.addEventListener('scroll', function(){}) // 页面滚动事件

            鼠标事件区别
                mousemove;         鼠标经过自身盒子会触发,经过子盒子也会触发
                mouseenter,mouseleave;        只有经过自身盒子会触发  // mouseenter不会冒泡
            
            动画函数封装
                // 通过定时器不断移动盒子的位置 元素要加定位 style.left赋值 
                参数: 动画对象,移动距离
                function animate(obj, target){
                    clearInterval(obj.timer)
                    obj.timer = setTimeout(function(){
                        if(obj.offestLeft >= target){
                            clearTimeout(timer);
                        }
                        obj.style.left = obj.offsetLeft + 1 + 'px';
                    },30)
                }
                缓动效果
                    缓动公式: (目标值-现在位置)/10
                    // 步长正的往大的取证，负的往小取整
                
                回调函数    
                    // 函数可以作为一个参数，将这个函数作为参数传递到另一个函数里面，当那个函数执行完之后，再执行传进去的这个函数就叫做回调函数
                    写在定时器结束的位置callback
            
            窗口滚动
                window.scroll(x, y)  // 返回页面中的某个位置   里面的xy不跟单位   


    移动端
        触屏事件touch
            touchstart      // 手指触摸触发
            touchmove       // 手指DOM元素移动触发
            touchend        // 手指离开触摸
                
        触摸事件对象
            TouchEvent
                touches    // 正在触摸屏幕的所有手指一个列表
                targetTouches     // 正在触摸当前DOM元素上的手指一个列表  
                changedTouches    // 手指状态发生了改变的列表，从无到有，从有到无
        
        移动端拖拽元素

                var div = document.querySelector('div');
                var startX = 0;
                var starty = 0;
                var x = 0;
                var y = 0;
                div.addEventListenter('touchstart', function(e){
                    // 获取手指初始坐标
                    startX = e.targetTouches[0].pageX;
                    startY = e.targetTouches[0].pageY;
                    x = this.offsetLeft;
                    y = this.offestTop;
                })
                div.addEventListenter('touchmove', function(e){
                    // 计算手指的移动距离  手指移动之后的坐标减去手指初始坐标
                    var moveX =  e.targetTouches[0].pageX - startX;
                    var moveY =  e.targetTouches[0].pageY - startY;
                    // 移动我们的盒子
                    this.style.left = x + moveX + 'PX';
                    this.style.Top = Y + moveY + 'PX';
                    // 阻止屏幕滚动默认行为
                    e.preventDefault();
                })

        
                
        移动端轮播图
            // 自动播放  手指拖动轮播图
            // 第一张 最后一张前后补图   CSS3
                transitionend;       过度完成事件

                classList;           返回元素的类名
                    element.classList.add('类名')     // 添加类在后面追加类，不会覆盖原有的类，'' 里面不需要加小点
                    element.classList.remove('类名')  // 单独删除其中的一个
                    element.classList.toggle('')     // 切换类名  有这个类就删除，没有就添加

        click延时解决问题
            禁用缩放  // user-scalable = no
            利用touch
            // 
            利用fastclick插件 

        本地存储
            // 数据存储在用户的浏览器中
            // 设置，读取方便，刷新页面不丢失数据
            // 容量大，sessionStorage约5M localStorage约20M
            // 中能存储字符串，可以将对象JSON.stringify()后存储

                window.sessionStorage
                    // 生命周期为关闭浏览器窗口
                    // 同一个窗口下数据可以共享
                    // 以键值对形式存储
                    sessionStorage.setItem('key',value)     // 存储数据
                    sessionStorage.getItem(key)         // 获取数据
                    sessionStorage.removeItem(key)          // 删除数据
                    sessionStorage.clear()              // 删除所有数据
                
                window.localStorage
                    // 生命周期永久有效
                    // 可以多个窗口共享（同一浏览器可以共享）
                    // 以键值对的形式存储使用
                    localStorage.setItem('key',value)     // 存储数据
                    localStorage.getItem(key)         // 获取数据
                    localStorage.removeItem(key)          // 删除数据
                    localStorage.clear()              // 删除所有数据


ES6
    面向过程
        // 分析好步骤,一步步解决问题   性能高，没有面对对象容易维护
    面对对象
        // 找出对象,并写出这些对象的功能   易维护，易复用，性能比面对过程低
        // 对象是一组无序的相关属性和方法的集合，所有的事情都是对象，如 字符串，数值，数组，函数等
        封装性,继承性,多态性

        // 对象特指某一个,类抽象了对象的公共部分,泛指某一个大类   通过类的实例化一个具体的对象
        对象由属性和方法组成
                属性:事物的特征
                方法:事物的行为
        思维特点
            抽取对象共用的属性和行为组织(封装),成一个类(模板)
            对类进行实例化,获取类的对象
            // 考虑的是有哪些对象，按照面对对象的思维特点，不断的创建对象，使用对象，指挥对象做事情


        通过类实现面对对象编程        
        创建类        // 类是构造函数的另一种写法   
            class Star {

            }
            利用类创建对象,new 
                new Star();

            constructor(),是类的构造函数,用于接受传递参数同时返回实例对象
                // new 生成实例的时候自动调用这个函数 不写也会自动调用  
                // 不需要return 自动返回
               
                class Star {
                    constructor(uname, age) {
                        this.uname = uname;
                        this.age = age;
                    }
                    sing(song) {
                        console.log(this.name + song);
                    }
                }
                var ldh = new Star('刘德华', 18);
                var zxy = new Star('张学友', 20)
                ldh.sing('冰雨');
                zxy.sing ('ss')
                // 1.构造函数不需要function
                // 2.多个函数方法之间不需要逗号分隔

        类的继承extends
            // 子类可以继承父类的一些属性和方法   
                class Father {
                    constructor() {
        
                    }
                    money() {
                        console.log(100);
        
                    }
                }
                class Son extends Father {
        
                }
                var son = new Son();
                son.money();
            // super关键字  可以让子类访问和调用对象父类上的函数，可以调用父类的构造函数 
                class Father {
                    constructor(x, y) {
                        this.x = x;
                        this.y = y;
                    }
                    sum() {
                        console.log(this.x + this.y);
        
                    }
                }
                class Son extends Father {
                    constructor(x, y) {
                        super(x, y); //调用了父类中的构造函数
                    }
                }
                var son = new Son(1, 2);
                var son1 = new Son(11, 22);
                son.sum();
                son1.sum();
            // 继承中，实例化子类输出一个方法，先看子类有没有，再看父类，就近原则
            // super 必须在子类this之前调用 才能使用父类的方法
                class Father {
                    constructor(x, y) {
                        this.x = x;
                        this.y = y;
                    }
                    sum() {
                        console.log(this.x + this.y);
                    }
                }
                class Son extends Father {
                    constructor(x, y) {
                        super(x, y);
                        this.x = x;
                        this.y = y;
                    }
                    subtract() {
                        console.log(this.x - this.y);
                    }
                }
                var son = new Son(5, 3);
                son.subtract();
                son.sum();
            // 在ES6里面没有变量提升，必须现有类才能通过类实例化对象
            // 类里面的共有属性和方法一定要加this使用 this.uname  参数传递除外    
        
        
    添加元素
        element.insertAdjacentHTML(position, text); //  element 父元素  position 相对于父元素  以字符串形式追加
            beforbegin      // 元素自身的前面
            afterbegin      // 插入元素内部的第一个子节点之前
            beforeend       // 插入元素内部最后一个子节点之后
            afterend        // 元素自身的后面

        // (1) 创建li元素和section元素 
        var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>';
        var section = '<section class="conactive">测试 ' + random + '</section>';
        // (2) 把这两个元素追加到对应的父元素里面
        that.ul.insertAdjacentHTML('beforeend', li);
        that.fsection.insertAdjacentHTML('beforeend', section);
    
    
    ES5通过构造函数+原型实现面对对象编程
    构造函数
        // ES5创建类的方式
        构造函数创建对象
            // 构造函数名首字母必须大写  不需要return 就可以返回结果
                function 构造函数名(形参, 形参){
                    this.属性 = 值;
                    this.方法 = function() {

                    }
                }
            调用函数 
                // 调用函数后就可以使用对象里面的属性和方法
                var xx = new 构造函数名(实参, 实参);
                    /* new执行过程
                            new 构造函数可以在内存中创建了一个空的对象
                            this 指向刚才创建的空对象
                            执行构造函数里面的代码，给空对象添加属性和方法
                            返回这个对象  */

            调用属性有两种寻址方式
                // 对象名.属性名    
                    obj.lastname;
                // 对象名['属性名']
                    obj["lastname"];

        静态成员
            // 在构造函数本上添加的成员，只能由构造函数本身来访问
        实例成员
            // 在构造函数内部创建的对象成员， 只能由实例化对象来访问  通过this添加的成员 

        构造函数,原型对象prototype
            // 构造函数通过原型分配的函数时所有对象所共享的  共享方法   优化了了内存问题
            把不变的方法直接定义在prototype,这样所有的对象实例就可以共享这些方法
                Star.prototype.sing = function () {
    
                }
            
            // 一般情况下,公共属性定义到构造函数里面,公共的方法放到原型对象身上

        对象原型_proto_
            // 指向构造函数的prototype原型对象

            .constructor  
            // 主要记录该对象引用哪个构造函数    可以让原型对象重新指回原来的构造函数

            Star.prototype = {
                // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
                constructor: Star,
                sing: function() {
                    console.log('我会唱歌');
                    },
                movie: function() {
                    console.log('我会演电影');
                    }
                }
            
        原型链
            // 1. 只要是对象就有__proto__ 原型, 指向原型对象
            // 2. 对象实例原型指向 Star原型对象.prototype
            // 2. Star原型对象里面的__proto__原型指向的是 Object.prototype
            // 3. Object.prototype原型对象里面的__proto__原型  指向为 null        
          
          成员查找机制
            当访问要给对象的属性(包括方法),首先查找这个对象自身有没有该属性
            没有就查找他的原型(也就是__proto__指向的prototype原型对象)
            还没有就查找原型对象的原型(Object的原型对象)
            依次类推一直找到Object为止(null)
            // 就近原则

        this的指向问题
            // constructor里面的this 指向的是创建的实例对象 
            // 方法里面的this 指向这个方法的调用者，可以是按钮
            // 原型对象函数里面的this 指向的是 实例对象

        扩展内置对象
            // 通过原型对象，对原来的内置对象进行扩展自定义的方式  比如给数组增添自定义求偶数的功能
            // 数组和字符串内置对象不能给原型对象覆盖操作  Array.prototype = {}  只能是Array.prototype.xxx = function() {} 不然会覆盖掉原先的

        call()
            调用这个函数,并修改函数运行时的this指向
                fn.call(thisArg, arg1, arg2, ...)
                    // thisArg    当前调用函数this的指向对象
                    // arg1,arg2  传递的其他参数
                // call() 可以调用函数
        
        ES5借助构造函数继承父类型
            构造函数+原型对象实现继承,被称为组合继承
            // 父构造函数
                function Father (uname, age){
                    this.uname = uname;
                    this.age = age;              // this指向父构造函数实例
                    Father.prototype.money = function() {
                        console.log(100000);
                    }
                }
            // 子构造函数
                function Son(uname, age) {
                    Father.call(this, uname, age) // this指向子构造函数对象实例
                    Son.prototype = new Father();
                    Son.prototype.constructor = Son; 
                }

        借助构造函数继承父类型属性
            Father.call(this, uname, age)
        借助构造函数继承父类型方法
            Son.prototype = new Father();    // 将son的原型对象指向Father的实例对象 实例对象_proto_可以访问Father原型对象  ！原型链
            Son.prototype.constructor = Son; 

    ES5新增方法
        数组方法
            迭代方法
                遍历数组forEach()
                    Array.forEach(function(Value, index, arr){

                    })
                    // Value  数组当前项的值
                    // index  数组当前索引号
                    // arr   数组对象本身

                筛选数组Filter()
                    Array.filter(function(Value, index, arr){
                            return value >= 20;
                            // 创建一个新的数组，新数组中的元素通过检测指定数组中符合条件的所有元素   
                            // 直接返回一个新的数组
                    })          
                    // Value  数组当前项的值
                    // index  数组当前索引号
                    // arr   数组对象本身

                检测数组中的元素是否满足指定条件some()
                    Array.some(function(Value, index, arr){
                        return vlaue == 20;
                        // 返回值是布尔值  如果找到这个元素就返回true  查找不到就返回false
                        // 如果找到第一个满足的条件元素，则循环终止，不继续查找      如查询数组中唯一的元素，用SOME更合适，因为找到了就停止循环效率更高
                        Array.some(function(value) {
                            if(value.pname === product.value){
                                console.log(value);
                                return true;
                            }
                        })
                    })
                    // Value  数组当前项的值
                    // index  数组当前索引号
                    // arr   数组对象本身
                every()

        字符串方法
            从一个字符串的两端删除空白字符trim()
                str.trim()
                // 并不影响字符串本身，他返回一个新的字符串
                
        对象方法
            定义对象中新的属性或修改原有的属性Object.defineProperties()
                Object.defineProperty(obj, prop, descriptor);
                // obj（必须）   目标对象
                // prop（必须）    需要定义或修改的属性的名字
                /*  descriptor（必须）   目标属性所拥有的特性      以花括号的形式来书写
                        value   设置的属性的值  默认为undefined
                        writable   值是否可以重写  true/false 默认为false
                        enumerable    目标属性是否可以被枚举(遍历)   true/false 默认为false
                        configurable    目标属性是否可以被删除或是否可以再次修改特性  true/false 默认为false    */
                    Object.defineProperty(obj, prop, {
                        value: 1000
                    })
    ES6函数                
    函数的定义
    // 所有的函数都是Function的实例对象
    // 函数也属于对象
        函数的申明方式function
            function fn(){

            }

        函数表达式(匿名函数)
            var fun = function(){

            }

        利用newFunction('参数1', '参数2', '函数体')
            // function 里面的参数必须是字符串格式
            var f = new Function('');


    函数的调用方式,thisd的指向
        普通调用
            fn()
            fn.call()
            // this指向window

        对象的方法
            var o = {
                sayHi: function(){

                }
            }
            o.sayHi()
            // this 指向对象o

        构造函数
            function Star() {};
            new Star();
            // this 指向new 的实例对象
            // 原型对象this 指向的也是实例对象

        绑定事件的函数
            btn.onclick = function() {}
            点击调用
            // this 指向函数的调用者

        定时器函数
            setInterval(function(){

            }, 1000)
            每隔一秒钟自己调用
            // this指向 window

        立即执行函数
            (function(){

            })();
            最后一个小括号相当于自己调用这个函数,可以用于接受一个参数
            // this指向  window
    
    改变函数内部的this指向
        call()
            fun.call(thisArg, arg1, arg2, ...)  // call() 可以调用函数  
            // thisArg    当前调用函数this的指向对象
            // arg1,arg2  传递的其他参数
          主要作用为实现继承

        apply()
            fun.apply(thisArg, [argsArray])     // apply() 可以调用函数
            // thisArg  在fun函数运行时的this值
            // argsArray  传递的值，必须以数组的形式（伪数组）
            // 返回值就是函数的返回值， 因为它是调用函数
          主要应用搭配数学内置对象求值
            利用apply借助于数学内置对象求最大值
                var arr = [1, 66, 3, 99, 4];
                var max = Math.max.apply(Math, arr);

        bind()
            fun.bind(thisArg, arg1, arg2)       // bind() 不会调用函数  
            // thisArg  在fun函数运行时的this值   
            // arg1,arg2  传递的其他参数
            // 返回原函数改变this之后产生的新函数
          有的函数不需要立即调用,但是又想改变函数内部的this指向 // 按钮点击后禁用3秒后开启
            var btn = document.querySelector('button');
            btn.onclick = function() {
                this.disabled = true;
                setTimeout(function(){
                    this.disabled = false;
                }.bind(this), 3000)
            }
             
    严格模式
        // ie10以上  消除了javacript语法的一些不合理，不严谨之处
        // 必须用var声明变量
        // 禁止自定义的函数中的this指向window
        // 创建eval作用域
        // 对象不能有重名的属性

        为脚本开启严格模式
          // 下面Js代码就会按照严格模式执行代码
            // 1.
                'use strict'
            // 2. 创建一个独立的作用域不影响其他的script 脚本文件
                (function(){
                    'use strict';
                    JS代码
                })()
        
        为函数开启严格模式
            function fn() {
                'use strict';
            }

    高阶函数
        高阶函数是对其他函数进行操作的函数
        // 1.接收函数作为参数
            function fn(){

            }
        // 2.将函数作为返回值输出
            function fn() {
                return function() {}
            }
    generator
    //把异步回调代码变成同步代码
        // 除return外,可以用yield返回多次
        function* foo(x) {
            yield x + 1;
            yield y + 1;
            return x + 3;
        }
        // foo(5) 仅仅是创建了一个generator对象，还没有去执行他
        调用方法 
            function* fib(max) {
                var
                    t,
                    a = 0,
                    b = 1,
                    n = 0;
                while (n < max) {
                    yield a;
                    [a, b] = [b, a + b];
                    n ++;
                }
                return;
            }
            // 1 
            不断调用generator对象的next()
            var f = foo(5);
            f.next();
            f.next();
            // next()方法会执行generator的代码，然后，每次遇到yield x;就返回一个对象{value: x, done: true/false}
            // 然后“暂停”。返回的value就是yield的返回值，done表示这个generator是否已经执行结束了
            // 如果done为true，则value就是return的返回值

            // 2  for...of
            循环迭代generator对象,不需要我们自己判断done
            for (var x of fib(10)) {
                console.log(x); // 依次输出0, 1, 1, 2, 3, ...
            }
            
    闭包
        // 闭包是函数  作用是延申变量范围
        指有权访问另一个函数作用域中变量的函数
           function fn() {
               var num = 10;
               function fun() {
                   console.log(num);
               }
           }

        // 例 循环注册点击事件 点击li输出当前li的索引号
        // 立即执行函数称为小闭包， 立即执行函数里面任何一个函数都可以使用它的i变量
           for(var i = 0; i<lis.length; i++) {
               // 利用for循环创建四个立即执行函数
               (function(i){
                lis[i].onclick = function() {
                    console.log(i);
                }
               })(i);
           }

        // 例 循环中的定时器
            for(var i = 0; i<lis.length; i++) {
                (function(i){
                    setTimeout(function(){
                        console.log(lis[i].innerHTML);
                    }, 3000)
                })(i);
            } 
            

    递归
      一个函数在内部可以调用其本身
      // 容易发色栈溢出错误  必须要加退出条件  return
            function fn() {
                fn();
                return;
            }
        // 例 利用递归求阶乘
            function fn(n) {
                if(n == 1) {
                    return 1;
                }
                return n * fn(n - 1);
            }
        // 例子 1.1.2.3.5.8....序列 斐波那契数列求N项
            function fn(n) {
                if(n == 1 || n == 2){
                    return 1;
                }
                return fn(n-1) + fn(n-2);
            }
        
        浅拷贝
          浅拷贝只是拷贝一层,更深层次对象级别的只拷贝地址  // 深层只拷贝地址 修改拷贝之后的深层次，原来的也会被修改
            Object.assign(target, sources);
                // target 目标，拷贝给谁
                // sources  拷贝对象
                只有一级属性是深拷贝
                一级属性里面有引用数据类型则是浅拷贝

                for (var k in obj) {
                         // k 是属性名   obj[k] 属性值
                    // o[k] = obj[k]
                }
                

        深拷贝
          深拷贝拷贝多一层每一级别的数据都会拷贝    // 从新开辟了一个空间   修改拷贝完的  原来的不变
          
            // 列 利用递归深拷贝
                function deepCopy(newobj, oldobj) {
                    for (var k in oldobj) {
                        // 判断我们的属性值属于那种数据类型
                        // 1. 获取属性值  oldobj[k]
                        var item = oldobj[k];
                        // 2. 判断这个值是否是数组
                        if (item instanceof Array) {
                            newobj[k] = [];
                            deepCopy(newobj[k], item)
                        } else if (item instanceof Object) {
                            // 3. 判断这个值是否是对象
                            newobj[k] = {};
                            deepCopy(newobj[k], item)
                        } else {
                            // 4. 属于简单数据类型
                            newobj[k] = item;
                        }
                    }
                }
                deepCopy(o, obj);

    正则表达式
        用于匹配字符串中字符组合的模式  // 正则表达式也是对象    不需要加引号不管是数字型还是字符串型
            // 通常用来检索，替换那些符合某个模式的文本，例如表单验证   过滤页面内容中的敏感词汇     或者从字符串中获取我们想要的特定部分
        
        创建正则表达式
            RegExp对象函数
                var 变量名 = new Regexp(/表达式/);

            利用字面量创建  // 主要使用
                var 变量名 = /表达式/;

        测试正则表达式
            test()   // 用于检测字符串是否符合该规则  返回true / false
                regexObj.test(str)
                    // regexObj  正则表达式变量名
                    // str 我们要测试的文本

        特殊字符
            // 也被称为元字符 ^ $ + 等  特殊意义符号    在MDN查找特殊字符含义   菜鸟工具
            边界符
                // ^ 表示匹配行首的文本，以谁开始
                // $ 表示匹配行尾的文本，以谁结束
            字符类
                // []  表示一系列字符可供选择，只要匹配其中一个就可以了
                // [-]  方括号内部范围符-
                // [a-zA-Z0-9] 字符组合
                // [^a-z]  里面的^表示取反 表示不能包含
                // [^a-z$]  多选一
            量词符
                // 用来设定某个模式的出现次数 [^a*&]   量词中间不要有空格
                // *  >= 0 
                // +  >= 1  
                // ?  1 || 0  重复0次或1次
                // {3}  重复3次
                // {3,}  大于等于3
                // {3,16}   大于等于3 且 小于等于16

              小括号表示优先级
                var reg = /^(abc){3}$/  // 表示abc重复三次
        
            预定义类
                //  \d  匹配0-9之间的任一数字   相当于[0-9]
                //  \D  匹配所有0-9以外的字符   相当于[^0-9]
                //  \w  匹配任意的字母，数字，下划线， 相当于[A-Za-z0-9_]
                //  \W  除所有的字母，数字，下划线以外的字符， 相当于[^A-Za-z0-9_]
                //  \s  匹配空格(包括  换行符，制表符，空格符等)  相当于[\t\r\n\v\f]
                //  \S  匹配非空格字符   相当于[^\t\r\n\v\f]

        // 案例表单验证
            var uname = document.querySelector('.uname');
            var reg = /^[a-zA-Z0-9_-]{6,16}$/;
            var span = document.querySelector('span');
            uname.onblur = function() {
                if(reg.test(this.value)) {
                    console.log('正确的');
                    span.className = 'right';
                    span.innerHTML = '用户名格式输入正确';
                }
                else{
                    console.log('错误的');
                    span.className = 'wrong';
                    span.innerHTML = '用户名格式输入正确';
                }
            }
        
        正则替换
            替换字符串replace()  
                String.replace(regexp,replace())
                // 第一个参数    被替换的字符串 或者 正则表达式
                // 第二个参数    替换的字符串  或者  正则表达式
                // 返回值是一个替换完毕的新字符串    

            // 敏感词过滤
                var text = document.querySelector('textarea');
                var btn = document.querySelector('button');
                btn.onclick = function() {
                    text.replace(/激情|SB/g,'**');
                }

        正则表达式参数
            /表达式/(修饰符)
            // switch也称作修饰符，按照什么样的模式来匹配
            // g  全局匹配
            // i  忽略大小写
            // gi  全局匹配和忽略大小写
    
    ES6
        let关键字
            声明变量
            let a = 10;
        // let 声明的变量只在所处的块级有效  块级作用域{}
        // 不存在变量提升 只能先声明再使用
        // 暂时性死区  和作用区域绑定不受外部影响
                var num = 10;
                if(true) {
                    console.log(num);
                    let num = 20;
                }
            // num 和他所在块级区域绑定，先输出再定义报错未声明

            经典面试题
            /*  var arr = [];
                for(var i = 0; i<2; i++){
                    arr[i] = function() {
                        console.log(i);
                    }
                }  
                arr[0]();
                arr[1]();
                2
                2
                */
                当前变量i都是全局的,函数执行时输出的都算全局作用域下的值,此时FOR循环早已完成

            /*  let arr = [];
                for(let i = 0; i<2; i++){
                    arr[i] = function() {
                        console.log(i);
                    }
                }  
                arr[0]();
                arr[1]();
                0
                1
                */
                每次循环都会产生一个块级作用域,每个块级作用域i是不同的

        const关键字
            声明常量,常量的值就是不能变化的值
                const a = 10;
            // 具有块级作用域
            // 声明常量时必须赋初始值  、
            // 赋值后不能修改(对应的内存地址不可更改)  复杂数据类型里面的值可以修改 对他重新赋值是不可以的
                const ary = [100, 200];
                ary[0] = 123;
                ary = [123, 200];
                ary = [1, 2];报错
        
        解构赋值
            // 允许从数组中提取值,按照对应位置,对应变量赋值,对象也可以实现解构

            数组解构
                按照一一对应的关系从数组中提取值然后将值赋值给变量
                let ary = [1, 2, 3]
                let [a, b, c, d] = ary;  // 第一个[]是解构  如果解构不成功，变量值为undefined(d)
            
            对象解构
              // 1
                let person =  { name:'zhangsan',
                                age: 20
                                }
                let {name, age} = person;
              // 2
                let {name: myname, age: myage} = person; // myname myage 属于别名，name匹配person name 属性 然后赋值给右侧变量

        箭头函数
            用来简化函数定义语法的
            // 箭头函数不能用 argument  ...args 参数前面加...代表接受所有的实参
            const fn=(形参) => {函数体}
                // 函数体只有一句代码且执行结果就是返回值，可以省略大括号
                    function sum(num1, num2) {
                        return num1 + num2;
                    }
                    const sum = (num1, num2) => num1 + num2;
                // 如果形参只有一个，可以省略小括号
                    function fn(v) {
                        return 4*v;
                    }
                    const fn = v => 4*v;
            
            箭头函数this问题
                // 箭头函数不绑定this  箭头函数中的this，指向的是函数定义位置的上下文this

            // 面试题
               var obj = {
                   age: 20,
                   say: () => {
                       alert(this.age)
                   }
               }
               obj.say()
               undefined // 对象不能产生作用域  say方法实际被定义在全局作用域下 say 方法中的this指向widow
        
        剩余参数
            函数实参个数大于形参个数时将剩余的实参放到数组中
               function sum (fisr, ...args) {
                   console.log(first); // 10
                   console.log(args);  // [20, 30]
               }
               sum(10, 20, 30);

            剩余参数和解构配合使用
               let students = ['wangwu','zhangsan', 'lisi'];
               let [s1, ...s2] = students; 
               console.log(s1);  // ['wangwu']
               console.log(s2);  // ['zhangsan', 'lisi']
        
        数组的扩展方法
            // ...ary  1, 2, 3
            // 将 数组 对象 转为用逗号风格的参数序列
               let ary = [1, 2, 3];
                console.log(...ary); // 1 2 3
                console.log(1, 2, 3);  // 1 2 3  参数分隔符不显示

            扩展运算符应用于合并数组
               let ary1 = [1, 2, 3];  
               let ary2 = [4, 5, 6];
               let ary3 = [...ary1, ...ary2];
            
            将伪数组,可遍历对象转换为真正的数组  // 转换后可以调用方法
               let oDivs = document.getElementsByTagName('div');
                    var ary = [...oDivs];
            
            构造函数的方法
               Array.from()
               // from()  接收一个伪数组  转换成一个真正的数组
            
            find()
               找出第一个复合条件的数组成员,没有找到返回undefined
                    ary.find(item => item == 2);

            findindex()
               找出第一个复合条件的数组成员位置,没有找到返回-1
                    ary.findindex(item => item > 15);
                
            includes()
                表示某个数组是否包含给定的值,返回布尔值    
                    ary.includes(2);

        字符串的扩展方法
            模板字符串
               // 新增创建字符串的方法,使用反引号定义
                let name = `zhangsan`;
               // 使用${} 拼接
                let sayHello = `hello my name is ${name}`;
               // 模板字符串中可以换行显示
               // 模板字符串可以调用函数
                let greet = `${fn()}`;

            startsWith()
               判断参数字符串是否在原字符串的头部       // 返回布尔值
                str.startsWith('hello');
            endsWith()
               判断参数字符串是否在原字符串的尾部
                str.endsWith('!');

            repeat()
               表示将原字符串重复N次,返回一个新字符串
                'x'.repeat(3);

        Set()
            新的数据结构,类似于数组,成员唯一,没有重复的值  // 搜索框搜索相同内容不存储显示
            // 本身是一个构造函数
               const s = new Set();
            // 可以接受一个数组作为参数 用来初始化
               const set = new Set([1, 2, 3, 4]);
            // 可以用作数组去除， 去除重复的数组值
        
            方法
                s.add(value)
                    添加某个值,返回Set结构本身
                s.delete(value)
                    删除某个值,返回一个布尔值表示删除是否成功
                s.has(value)
                    返回一个布尔值,表示该值是否为Set成员
                s.clear()
                    清除所有成员,没有返回值下
        
        Symbol
            // 独一无二的值  就算参数相同也不相等
            //  Symbol 函数前不能使用NEW命令，否则会报错

            Symbol.prototype.description
            // 直接返回Symbol的描述

        promises
        // 异步编程的解决方案
            // 接受一个函数作为参数 该函数的参数分别是resolve, reject
            const promise = new Promise(function(resolve, reject){
                // some code
                if (s){ // 条件时异步操作成功
                    resolve(value);
                    // resolve函数将Promise对象的状态从 未完成 变为 成功 
                    // 在异步操作成功时调用 并将异步操作的结果传递出去
                }else {
                    reject(error);
                    // reject函数将Promise对象的状态从 未完成 变为 失败 
                    // 在异步操作失败时调用 并将异步操作报出的错误传递出去
                }
            })
            // promise新建就会立即执行
            
          promise实例生成后可以用then方法分别指定resolved状态和rejected状态
          // then方法指定的回调函数在当前脚本的同步任务执行完后才会执行
            // 接收两个回调函数作为参数
            promise.then(function(value){
                //success
                // promise状态变为resolved调用
            }, function(error){
                //failure
                // promise状态变为rejected调用
            })
        
          promise.catch()
          // 指定发生错误时的回调函数

          promise.finally()
          // 不管promise对象最后状态如何，都会执行的操作

          promise.all()
          // 将多个promise实例包装成一个新的promise实例
Json
  数据交换格式

    数据的书写格式
        "name" : "菜鸟教程"

    对象在大括号中书写
        { "name":"菜鸟教程" , "url":"www.runoob.com" }
        // 使用点号来访问对象的值
            var myObj, x;
            myObj = { "name":"runoob", "alexa":10000, "site":null };
            x = myObj.name;
        // 使用 for-in 来循环对象的属性的值
        var myObj = { "name":"runoob", "alexa":10000, "site":null };
        for (x in myObj) {
            document.getElementById("demo").innerHTML += myObj[x] + "<br>";
        }
        // 修改值
        myObj.sites.site1 = "www.google.com";
        // 使用delete删除对象属性    
        delete myObj.sites.site1;

    数组
        {
        "name":"网站",
        "num":3,
        "sites":[ "Google", "Runoob", "Taobao" ]
        }
        // 使用索引值来访问数组
        x = myObj.sites[0];
        // 使用 for-in 来访问数组
        for (i in myObj.sites) {
            x += myObj.sites[i] + "<br>";
        }
        // 使用索引值来修改数组值
        myObj.sites[1] = "Github"
        // 使用 delete 关键字来删除数组元素
        delete myObj.sites[1];

    
 // js对象、数组转换为JSON对象、数组
    JSON.stringify(value[, replacer[, space]])
    // value: 必需， 要转换的 JavaScript 值（通常为对象或数组）。
    // replacer:可选。用于转换结果的函数或数组。
    JSON不允许包含函数,JSON.stringify();会删除JavaScript对象的函数

// json对象、数组转换为 js对象、数组
    JSON.parse(text[,reviver])
        // text 必须，一个有效的字符串
        // reviver  可选，一个转换结果的函数  将为对象的每个成员调用此函数
    

ajax
    异步javascript和xml
    // 创建快速动态网页，后台与服务器进行少量的数据交换，实现异步更新

    创建XMLHttpRequest对象
        // 用于后台与服务器交换数据，不加载网页的情况下，对网页某部分进行更新
        variable = new XMLHttpRequest();  
      老版本
        variable=new ActiveXObject("Microsoft.XMLHTTP");
    
        var xmlhttp;
        if (window.XMLHttpRequest)
        {
            //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
            xmlhttp=new XMLHttpRequest();
        }
        else
        {
            // IE6, IE5 浏览器执行代码
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }

    XHR请求方法
      // xmlhttp.open("Get", "ajax_info.txt", ture)
        open(method,url,async)
            // method：请求的类型；GET 或 POST
            // url：文件在服务器上的位置（.txt  .xml .asp .php）
            // async：true（异步）或 false（同步） 
                // XMLHttpRequest 对象如果要用于 AJAX 的话，其 open() 方法的 async 参数必须设置为 true
                // async=true 时，请规定在响应处于 onreadystatechange 事件中的就绪状态时执行的函数
                // async=false 时，请不要编写 onreadystatechange 函数 - 把代码放到 send() 语句后面即可

      // xmlhttp.send();  
        send(string)
            // string：仅用于 POST 请求
    
        向请求添加HTTP头
            setRequestHeader(header,value)
            // header: 规定头的名称
            // value: 规定头的值
    
    XHR响应
        // 获得字符串形式的响应数据
        responseText
            // 使用
            document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

        // 获得 XML 形式的响应数据
        responseXML

    onreadystatechange事件
        // readyState 改变时，就会触发 onreadystatechange事件
        // readyState == 4 && xmlhttp.status == 200 表示响应已就绪
        readyState
            // 存有 XMLHttpRequest 的状态。从 0 到 4 发生变化
                    // 0: 请求未初始化 （还没有调用 open()）
                    // 1: 服务器连接已建立  还没发送（还没有调用 send()）
                    // 2: 请求已接收  （通常现在可以从响应中获取内容头）
                    // 3: 请求处理中  通常响应中已有部分数据可用了，但是服务器还没有完成响应的生成。
                    // 4: 请求已完成，且响应已就绪
        status
            // 200: "OK"
            // 404: 未找到页面
      // 实例   
        xmlhttp.onreadystatechange = function() {
            if(xmlhttp.readyState==4&&status==200){
                document.getElementById().innerHtml=xmlhttp.responseText
            }
        }

    
        